﻿using ETA.Entity;
using ETA.IRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using NHibernate.Linq;
using NHibernate;

namespace ETA.Repositories
{
    public class NhRepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : AEntity
    {
        // Methods
        public virtual int Count()
        {
            ISession Session = NHibernateHelper.GetSession();
            return this.GetAll().Count<TEntity>();
        }

        public virtual int Count(Expression<Func<TEntity, bool>> predicate)
        {
            ISession Session = NHibernateHelper.GetSession();
            return this.GetAll().Where<TEntity>(predicate).Count<TEntity>();
        }

        public virtual void Delete(TEntity entity)
        {
            ISession Session = NHibernateHelper.GetSession();
            Session.Delete(entity);
            Session.Flush();
        }

        public virtual void Delete(TPrimaryKey id)
        {
            ISession Session = NHibernateHelper.GetSession();
            TEntity local =Session.Load<TEntity>(id);
            Session.Delete(local);
            Session.Flush();
        }

        public virtual void LogincDelete(TPrimaryKey id)
        {
            ISession Session = NHibernateHelper.GetSession();
            var current = this.FirstOrDefault(id);
            if (current != null)
            {
                current.IsDelete = true;
                current.ModifyDate = DateTime.Now;
                this.Update(current);
            }
        }

        public virtual TEntity FirstOrDefault(TPrimaryKey key)
        {
            ISession Session = NHibernateHelper.GetSession();
            return Session.Get<TEntity>(key);
        }

        public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return this.GetAll().FirstOrDefault<TEntity>(predicate);
        }

        public virtual TEntity Get(TPrimaryKey key)
        {
            TEntity local = this.FirstOrDefault(key);
            if (local == null)
            {
                throw new Exception(string.Concat(new object[] { "Threre is no such an entity with given primary key. Entity type: ", typeof(TEntity).FullName, ", primary key: ", key }));
            }
            return local;
        }

        public virtual IQueryable<TEntity> GetAll()
        {
            ISession Session = NHibernateHelper.GetSession();
            var res = Session.Query<TEntity>();
            Session.Flush();
            return res;
        }

        public virtual List<TEntity> GetAllList()
        {
            return this.GetAll().ToList<TEntity>();
        }

        public virtual List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate)
        {
            ISession Session = NHibernateHelper.GetSession();
            var res = this.GetAll().Where<TEntity>(predicate).ToList<TEntity>();
            Session.Flush();
            return res;
        }

        public virtual TEntity Insert(TEntity entity)
        {
            ISession Session = NHibernateHelper.GetSession();
            Session.Save(entity);
            Session.Flush();
            return entity;
        }

        public virtual TEntity Load(TPrimaryKey key)
        {
            ISession Session = NHibernateHelper.GetSession();
            return Session.Load<TEntity>(key);
        }

        public virtual long LongCount()
        {
            return this.GetAll().LongCount<TEntity>();
        }

        public virtual long LongCount(Expression<Func<TEntity, bool>> predicate)
        {
            return this.GetAll().Where<TEntity>(predicate).LongCount<TEntity>();
        }

        public virtual T Query<T>(Func<IQueryable<TEntity>, T> queryMethod)
        {
            return queryMethod(this.GetAll());
        }

        public virtual TEntity Single(Expression<Func<TEntity, bool>> predicate)
        {
            return this.GetAll().Single<TEntity>(predicate);
        }

        public virtual TEntity Update(TEntity entity)
        {
            ISession Session = NHibernateHelper.GetSession();
            Session.Update(entity);
            Session.Flush();
            return entity;
        }

        public virtual TEntity Merge(TEntity entity)
        {
            ISession Session = NHibernateHelper.GetSession();
             Session.Merge(entity);
            Session.Flush();
            return entity;
        }

        public string GenerateNo(string firestChar, int noType)
        {
            ISession Session = NHibernateHelper.GetSession();
            var strFormate = firestChar + "{0}";
            var generateNo = "";
            using (ITransaction tx = Session.BeginTransaction())
            {
                try
                {
                    var sql = @"SELECT TOP 1 [SerialNo] C FROM [SerialNo] WHERE NOTYPE={0}
                              UPDATE [SerialNo] SET [SerialNo]=[SerialNo]+1 WHERE NOTYPE={0}";
                    ISQLQuery query = Session.CreateSQLQuery(string.Format(sql, noType)).AddScalar("C", NHibernateUtil.Int64);
                    generateNo = Convert.ToInt32(query.UniqueResult()).ToString();
                    Session.Flush();
                    tx.Commit();
                }
                catch (HibernateException)
                {
                    tx.Rollback();
                    throw;
                }
            }
            return string.Format(strFormate, generateNo); ;
        }
    }

}
